# from fastapi import FastAPI, Request, Body
# from fastapi.responses import StreamingResponse
# import asyncio
# import json
#
# from pydantic import BaseModel
# from starlette.middleware.cors import CORSMiddleware
# from starlette.responses import HTMLResponse, JSONResponse
# from starlette.templating import Jinja2Templates
# from queue_manager import device_event_queue
#
# app = FastAPI()
#
# # 用队列保存将要推送给前端的设备命令
#
# templates = Jinja2Templates(directory="frontend")
# app.add_middleware(
#     CORSMiddleware,
#     allow_origins=["*"],  # 或者 ["http://localhost:63342"]
#     allow_credentials=True,
#     allow_methods=["*"],
#     allow_headers=["*"],
# )
#
#
# class DeviceCallPayload(BaseModel):
#     type: str
#     call_id: str
#     device_calls: list
#
#
# # @app.post("/api/device-call-result")
# # async def device_call_result(payload: dict = Body(...)):
# #     call_id = payload.get("call_id")
# #     result = payload.get("result")
# #
# #     print(f"[SSE] 收到设备操作结果: {call_id=} {result=}")
# #
# #     if call_id in device_response_futures:
# #         future = device_response_futures.pop(call_id)
# #         if not future.done():
# #             future.set_result(result)
# #             return {"success": True, "message": "结果已传回"}
# #     return JSONResponse(content={"success": False, "message": "无效的 call_id"}, status_code=400)
#
# @app.post("/api/push-device-call")
# async def push_device_call(payload: DeviceCallPayload):
#     print("[SSE] 收到设备指令:", payload.model_dump())
#     await device_event_queue.put(payload.model_dump())
#     print("[SSE] 接收到设备指令并放入队列:", payload.model_dump())
#     return {"success": True}
#
#
# @app.get("/show", response_class=HTMLResponse)
# async def show_dashboard(request: Request):
#     return templates.TemplateResponse("show.html", {"request": request})
#
#
# async def device_status_event_stream(request: Request):
#     print("执行了")
#     print(f"device_event_queue id in main: {id(device_event_queue)}")
#     while True:
#         if await request.is_disconnected():
#             print("[SSE] 客户端已断开连接，停止发送")
#             break
#         try:
#             data = await device_event_queue.get()
#             print("[SSE] 发送数据:", data)  # 新增调试打印
#             yield f"data: {json.dumps(data, ensure_ascii=False)}\n\n"
#         except asyncio.CancelledError:
#             print("[SSE] 取消错误，退出")
#             break
#
#
# @app.get("/api/device-status-stream")
# async def device_status_stream(request: Request):
#     print("[SSE] 开始发送数据")
#     print("当前事件循环FASTAPI:", asyncio.get_running_loop())
#     return StreamingResponse(device_status_event_stream(request), media_type="text/event-stream")
#
#
# if __name__ == "__main__":
#     import uvicorn
#     uvicorn.run(app, port=8080)
import asyncio
import json
import os

from dotenv import load_dotenv
from fastapi import FastAPI, Request, Body
from fastapi.responses import StreamingResponse
from pydantic import BaseModel
from redis.asyncio import Redis  # ✅ 官方推荐异步 Redis 客户端
from starlette.middleware.cors import CORSMiddleware
from starlette.responses import HTMLResponse, JSONResponse
from starlette.templating import Jinja2Templates

from queue_manager import device_event_queue  # 队列用于 SSE 推送

env = os.getenv("ENV", "dev")  # 默认测试环境
load_dotenv(f"../../.env.dev.{env}", override=True)
app = FastAPI()
redis = Redis(host="localhost", port=6379, decode_responses=True, password="2168")

templates = Jinja2Templates(directory="frontend")

app.add_middleware(
    CORSMiddleware,
    allow_origins=["*"],  # 或者具体 ["http://localhost:63342"]
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)


class DeviceCallPayload(BaseModel):
    type: str
    call_id: str
    device_calls: list


@app.post("/api/push-device-call")
async def push_device_call(payload: DeviceCallPayload):
    print("[SSE] 收到设备指令:", payload.model_dump())
    await device_event_queue.put(payload.model_dump())
    print("[SSE] 接收到设备指令并放入队列:", payload.model_dump())
    return {"success": True}


@app.post("/api/device-call-result")
async def device_call_result(payload: dict = Body(...)):
    call_id = payload.get("call_id")
    result = payload.get("result")

    print(f"[Result] 收到设备返回结果: call_id={call_id}, result={result}")

    if not call_id or result is None:
        return JSONResponse(content={"success": False, "message": "缺少 call_id 或 result"}, status_code=400)

    await redis.set(f"device_result:{call_id}", json.dumps(result), ex=120)  # 设置 2 分钟过期时间

    return {
        "success": True,
        "data": result
    }


@app.get("/show", response_class=HTMLResponse)
async def show_dashboard(request: Request):
    return templates.TemplateResponse("show.html", {"request": request})


async def device_status_event_stream(request: Request):
    print("[SSE] 启动设备事件流")
    print(f"device_event_queue ID: {id(device_event_queue)}")
    while True:
        if await request.is_disconnected():
            print("[SSE] 客户端断开连接")
            break
        try:
            data = await device_event_queue.get()
            print("[SSE] 推送数据:", data)
            yield f"data: {json.dumps(data, ensure_ascii=False)}\n\n"
        except asyncio.CancelledError:
            print("[SSE] 异步取消")
            break


@app.get("/api/device-status-stream")
async def device_status_stream(request: Request):
    print("[SSE] 客户端连接开始")
    return StreamingResponse(device_status_event_stream(request), media_type="text/event-stream")


if __name__ == "__main__":
    import uvicorn

    uvicorn.run(app, port=8080)
